package com.papers.juan.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.papers.common.constant.DictTypeConstants;
import com.papers.common.core.domain.PageQuery;
import com.papers.common.core.domain.entity.SysDictData;
import com.papers.common.core.page.TableDataInfo;
import com.papers.common.enums.GeneratePaperType;
import com.papers.common.enums.GenerateScopeType;
import com.papers.common.enums.PaperRecordType;
import com.papers.common.enums.YesOrNo;
import com.papers.common.exception.ServiceException;
import com.papers.common.helper.LoginHelper;
import com.papers.common.utils.BeanCopyUtils;
import com.papers.common.utils.DateUtils;
import com.papers.common.utils.JsonUtils;
import com.papers.common.utils.StringUtils;
import com.papers.juan.domain.TJuanGenerate;
import com.papers.juan.domain.TJuanGenerateDetail;
import com.papers.juan.domain.TJuanPaper;
import com.papers.juan.domain.TJuanPaperRecord;
import com.papers.juan.domain.bean.GenerateSaveBean;
import com.papers.juan.domain.bean.PaperQuestionInfoBean;
import com.papers.juan.domain.bean.QuestionQueryBean;
import com.papers.juan.domain.bean.QuestionTypeJsonBean;
import com.papers.juan.domain.bean.QuestionTypePropertyBean;
import com.papers.juan.domain.bo.TJuanGenerateBo;
import com.papers.juan.domain.vo.TJuanGenerateDetailVo;
import com.papers.juan.domain.vo.TJuanGenerateVo;
import com.papers.juan.domain.vo.TJuanPaperDetailVo;
import com.papers.juan.mapper.TJuanGenerateDetailMapper;
import com.papers.juan.mapper.TJuanGenerateMapper;
import com.papers.juan.mapper.TJuanPaperMapper;
import com.papers.juan.mapper.TJuanPaperRecordMapper;
import com.papers.juan.mapper.TJuanQuestionMapper;
import com.papers.juan.service.ITJuanGenerateService;
import com.papers.system.domain.TJuanChapter;
import com.papers.system.domain.TJuanCourse;
import com.papers.system.domain.TJuanKnowledge;
import com.papers.system.mapper.SysDictDataMapper;
import com.papers.system.mapper.TJuanChapterMapper;
import com.papers.system.mapper.TJuanCourseMapper;
import com.papers.system.mapper.TJuanKnowledgeMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 组卷Service业务层处理
 *
 * @author papers
 * @date 2022-10-08
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class TJuanGenerateServiceImpl implements ITJuanGenerateService {

    private final TJuanGenerateMapper tJuanGenerateMapper;

    private final TJuanPaperMapper tJuanPaperMapper;

    private final TJuanQuestionMapper tJuanQuestionMapper;

    private final TJuanPaperRecordMapper tJuanPaperRecordMapper;

    private final TJuanGenerateDetailMapper tJuanGenerateDetailMapper;

    private final SysDictDataMapper sysDictDataMapper;

    private final TJuanCourseMapper tJuanCourseMapper;

    private final TJuanChapterMapper tJuanChapterMapper;

    private final TJuanKnowledgeMapper tJuanKnowledgeMapper;

    /**
     * 最大题目随机次数（避免因设置不合理的组卷参数导致死循环）
     */
    private final static int MAX_RANDOM_TIMES = 100000;

    /**
     * 获取题量配比列表
     *
     * @param questionQueryBean 题目查询bean
     * @return 题量配比列表
     */
    @Override
    public List<QuestionTypePropertyBean> queryQuestionCountProportions(QuestionQueryBean questionQueryBean) {
        // 构建章节知识点的子节点id列表
        buildChapterKnowledgeChildIds(questionQueryBean);

        List<QuestionTypePropertyBean> list = tJuanQuestionMapper.queryQuestionCountProportions(questionQueryBean,
            DictTypeConstants.QUESTION_TYPE);
        if (0 == list.size()) {
            throw new ServiceException("当前考核范围下没有题目！");
        }
        return list;
    }

    /**
     * 获取自动生成题目列表
     *
     * @param generateId 组卷id
     * @return 是否生成成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean autoGeneratePaper(String generateId) {
        // 组卷信息
        TJuanGenerate juanGenerate = tJuanGenerateMapper.selectById(generateId);
        if (ObjectUtil.isEmpty(juanGenerate)) {
            throw new ServiceException("组卷信息不存在！");
        }
        // 组卷明细列表
        List<TJuanGenerateDetail> generateDetails = tJuanGenerateDetailMapper.selectList(new LambdaQueryWrapper<TJuanGenerateDetail>()
            .eq(StringUtils.isNotBlank(juanGenerate.getGenerateId()), TJuanGenerateDetail::getGenerateId, juanGenerate.getGenerateId())
            .orderByAsc(TJuanGenerateDetail::getQuestionType));
        if (0 == generateDetails.size()) {
            throw new ServiceException("组卷明细不存在！");
        }
        // 题目类型列表
        List<String> questionTypeList = generateDetails.stream().map(TJuanGenerateDetail::getQuestionType)
            .distinct().collect(Collectors.toList());
        // 题目范围列表（章节id列表/知识点id列表/试卷id列表）
        List<String> questionScopeList = Arrays.asList(juanGenerate.getGenerateScope().split(","));

        // 题目查询bean
        QuestionQueryBean questionQueryBean = new QuestionQueryBean();
        questionQueryBean.setCourseId(juanGenerate.getCourseId());
        questionQueryBean.setQuestionTypes(questionTypeList);
        // 所有题目列表，供随机选题
        List<PaperQuestionInfoBean> allQuestions = Lists.newArrayList();
        // 判断组卷范围（根据章节选题、知识点选题、试卷选题）
        if (GenerateScopeType.CHAPTER.getCode().equals(juanGenerate.getGenerateScopeType())) {
            questionQueryBean.setChapterIds(questionScopeList);
            // 构建章节的子节点id列表
            buildChapterKnowledgeChildIds(questionQueryBean);
            // 已选章节和已选题型下的所有题目
            allQuestions = tJuanQuestionMapper.queryAutoGenerateQuestions(questionQueryBean);
        } else if (GenerateScopeType.KNOWLEDGE.getCode().equals(juanGenerate.getGenerateScopeType())) {
            questionQueryBean.setKnowledgeIds(questionScopeList);
            // 构建知识点的子节点id列表
            buildChapterKnowledgeChildIds(questionQueryBean);
            // 已选知识点和已选题型下的所有题目
            allQuestions = tJuanQuestionMapper.queryAutoGenerateQuestions(questionQueryBean);
        } else if (GenerateScopeType.PAPER.getCode().equals(juanGenerate.getGenerateScopeType())) {
            // 构建多试卷的题目信息列表
            buildPapersQuestionInfos(questionScopeList, allQuestions);
        }

        // 试卷份数
        Integer generateNum = juanGenerate.getGenerateNum();
        // 试卷题目信息json列表
        List<String> paperQuestionInfoJsons = Lists.newArrayList();
        // 试卷总分
        Integer totalPaperScore;
        //相似题处理
        List<PaperQuestionInfoBean> totalQuestions = new ArrayList<>();//相似题处理结果
        //非相似集合
        List<PaperQuestionInfoBean> collect = allQuestions.stream().filter(item -> StringUtils.isEmpty(item.getRelevance())).collect(Collectors.toList());
        //相似题比较集合
        List<String> similaritys = collect.stream().map(PaperQuestionInfoBean::getQuestionCode).collect(Collectors.toList());
        totalQuestions.addAll(collect);
        //相似集合
        List<PaperQuestionInfoBean> allQuestion = allQuestions.stream().filter(item -> StringUtils.isNotEmpty(item.getRelevance())).collect(Collectors.toList());
        for (PaperQuestionInfoBean item:allQuestion) {
            String relevance = item.getRelevance();
            if(!similaritys.contains(relevance)){
                totalQuestions.add(item);
                similaritys.add(relevance);
                similaritys.add(item.getQuestionCode());
            }
        }
        if (1 == generateNum) {
            // 生成一张试卷
            totalPaperScore = generateSinglePaperMethod(paperQuestionInfoJsons, totalQuestions, generateDetails);
        } else {
            // 生成多张试卷
            totalPaperScore = generateMultiPapersMethod(paperQuestionInfoJsons, juanGenerate, totalQuestions, generateDetails);
        }
        // 批量新增试卷
        return insertPaperBatch(paperQuestionInfoJsons, juanGenerate, totalPaperScore);
    }

    /**
     * 根据试卷id列表获取题量配比列表
     *
     * @param paperIds 试卷ids
     * @return 题量配比列表
     */
    @Override
    public List<QuestionTypePropertyBean> queryPapersQuestionCountProportions(List<String> paperIds) {
        if (0 == paperIds.size()) {
            throw new ServiceException("试卷id列表不能为空！");
        }
        // 题量配比列表
        List<QuestionTypePropertyBean> list = Lists.newArrayList();
        // 试卷题目信息列表
        List<PaperQuestionInfoBean> questionInfoBeans = Lists.newArrayList();
        // 构建多试卷的题目信息列表
        buildPapersQuestionInfos(paperIds, questionInfoBeans);
        // key："题型_题目分数_难易程度", value: 总条数
        Map<String, Long> map = questionInfoBeans.stream().distinct().collect(Collectors.groupingBy(
            o -> o.getQuestionType() + "_" + o.getScore() + "_" + o.getQuestionEasy(), Collectors.counting()));
        // 构建题量配比列表
        buildQuestionCountProportions(list, map);
        // 题型、难易程度升序
        return list.stream().sorted(Comparator.comparing(QuestionTypePropertyBean::getQuestionType)
            .thenComparing(QuestionTypePropertyBean::getQuestionEasy)).collect(Collectors.toList());
    }

    /**
     * 查询组卷
     */
    @Override
    public GenerateSaveBean queryById(String generateId) {
        GenerateSaveBean generateSaveBean = new GenerateSaveBean();
        // 组卷基本信息
        TJuanGenerate juanGenerate = tJuanGenerateMapper.selectById(generateId);
        if (ObjectUtil.isEmpty(juanGenerate)) {
            throw new ServiceException("组卷信息不存在！");
        }
        BeanCopyUtils.copy(juanGenerate, generateSaveBean);

        // 范围类型（1章节选题/2知识点选题）
        String generateScopeType = juanGenerate.getGenerateScopeType();
        // 题目范围列表（章节id列表/知识点id列表/试卷id列表）
        List<String> questionScopeList = Arrays.asList(juanGenerate.getGenerateScope().split(","));
        // 题目范围名称列表（章节名称列表/知识点名称列表/试卷名称列表）
        List<String> questionScopeNames = null;
        if (GenerateScopeType.CHAPTER.getCode().equals(generateScopeType)) {
            List<TJuanChapter> juanChapters = tJuanChapterMapper.selectBatchIds(questionScopeList);
            questionScopeNames = juanChapters.stream().map(TJuanChapter::getChapterName).collect(Collectors.toList());
        } else if (GenerateScopeType.KNOWLEDGE.getCode().equals(generateScopeType)) {
            List<TJuanKnowledge> juanChapters = tJuanKnowledgeMapper.selectBatchIds(questionScopeList);
            questionScopeNames = juanChapters.stream().map(TJuanKnowledge::getKnowledgeName).collect(Collectors.toList());
        } else if (GenerateScopeType.PAPER.getCode().equals(generateScopeType)) {
            List<TJuanPaper> juanPapers = tJuanPaperMapper.selectBatchIds(questionScopeList);
            questionScopeNames = juanPapers.stream().map(TJuanPaper::getPaperName).collect(Collectors.toList());
        }
        generateSaveBean.setGenerateScopeNames(questionScopeNames);

        // 组卷明细列表
        List<TJuanGenerateDetail> generateDetails = tJuanGenerateDetailMapper.selectList(new LambdaQueryWrapper<TJuanGenerateDetail>()
            .eq(StringUtils.isNotBlank(juanGenerate.getGenerateId()), TJuanGenerateDetail::getGenerateId, juanGenerate.getGenerateId())
            .orderByAsc(TJuanGenerateDetail::getQuestionType));
        generateSaveBean.setGenerateDetails(generateDetails);

        // 题目类型属性列表
        List<QuestionTypePropertyBean> propertyBeanList = BeanCopyUtils.copyList(generateDetails, QuestionTypePropertyBean.class);
        generateSaveBean.setPropertyBeanList(propertyBeanList);

        return generateSaveBean;
    }

    /**
     * 获取组卷列表
     *
     * @param bo        过滤条件
     * @param pageQuery 分页推荐
     * @return 组卷列表
     */
    @Override
    public TableDataInfo<TJuanGenerateVo> queryJuanGenerateList(TJuanGenerateBo bo, PageQuery pageQuery) {
        Page<TJuanGenerateVo> result = tJuanGenerateMapper.queryJuanGenerateList(bo, pageQuery.build());
        return TableDataInfo.build(result);
    }

    /**
     * 根据组卷id获取组卷详情
     *
     * @param generateId 组卷id
     * @return 组卷详情
     */
    @Override
    public TJuanGenerateDetailVo queryJuanGenerateDetailById(String generateId) {
        // 组卷信息
        TJuanGenerate tJuanGenerate = tJuanGenerateMapper.selectById(generateId);
        // 组卷详情
        TJuanGenerateDetailVo tJuanGenerateDetailVo = new TJuanGenerateDetailVo();
        BeanCopyUtils.copy(tJuanGenerate, tJuanGenerateDetailVo);

        // 试卷详情列表
        List<TJuanPaperDetailVo> tJuanPaperDetailVos = tJuanPaperMapper.queryPaperDetailListByGenerateId(generateId);
//        tJuanGenerateDetailVo.setJuanPaperDetails(tJuanPaperDetailVos);

        return tJuanGenerateDetailVo;
    }

    /**
     * 查询组卷列表
     */
    @Override
    public List<TJuanGenerateVo> queryList(TJuanGenerateBo bo) {
        LambdaQueryWrapper<TJuanGenerate> lqw = buildQueryWrapper(bo);
        return tJuanGenerateMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<TJuanGenerate> buildQueryWrapper(TJuanGenerateBo bo) {
//        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<TJuanGenerate> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getGenerateId()), TJuanGenerate::getGenerateId, bo.getGenerateId());
        lqw.eq(StringUtils.isNotBlank(bo.getGenerateType()), TJuanGenerate::getGenerateType, bo.getGenerateType());
        lqw.eq(StringUtils.isNotBlank(bo.getGenerateQuestionType()), TJuanGenerate::getGenerateQuestionType, bo.getGenerateQuestionType());
        lqw.eq(StringUtils.isNotBlank(bo.getGenerateQuestionNum()), TJuanGenerate::getGenerateQuestionNum, bo.getGenerateQuestionNum());
        lqw.eq(bo.getGenerateNum() != null, TJuanGenerate::getGenerateNum, bo.getGenerateNum());
        lqw.eq(StringUtils.isNotBlank(bo.getGenerateRule()), TJuanGenerate::getGenerateRule, bo.getGenerateRule());
        lqw.eq(bo.getGenerateEasy() != null, TJuanGenerate::getGenerateEasy, bo.getGenerateEasy());
        lqw.eq(bo.getGenerateRepeat() != null, TJuanGenerate::getGenerateRepeat, bo.getGenerateRepeat());
        lqw.eq(StringUtils.isNotBlank(bo.getGenerateScope()), TJuanGenerate::getGenerateScope, bo.getGenerateScope());
        lqw.eq(StringUtils.isNotBlank(bo.getCreatedBy()), TJuanGenerate::getCreatedBy, bo.getCreatedBy());
        lqw.eq(bo.getCreatedTime() != null, TJuanGenerate::getCreatedTime, bo.getCreatedTime());
        lqw.eq(StringUtils.isNotBlank(bo.getUpdatedBy()), TJuanGenerate::getUpdatedBy, bo.getUpdatedBy());
        lqw.eq(bo.getUpdatedTime() != null, TJuanGenerate::getUpdatedTime, bo.getUpdatedTime());
        return lqw;
    }

    /**
     * 新增组卷
     */
    @Override
    public Boolean insertByBo(GenerateSaveBean saveBean) {
        List<TJuanGenerateDetail> generateDetails = saveBean.getGenerateDetails();
        int paperTotalScore = generateDetails.stream().mapToInt(o -> o.getQuestionNum() * o.getQuestionScore()).sum();
        if (paperTotalScore != saveBean.getPaperTotalScore()) {
            throw new ServiceException("题目总分与试卷总分不一致！");
        }
        // 组卷信息
        TJuanGenerate juanGenerate = BeanUtil.toBean(saveBean, TJuanGenerate.class);

//        juanGenerate.setGenerateEasy(getGenerateEasy(saveBean.getGenerateDetails()));
        juanGenerate.setCreatedBy(String.valueOf(LoginHelper.getUserId()));
        juanGenerate.setCreatedTime(DateUtils.getNowDate());
        if (ObjectUtil.isEmpty(generateDetails)) {
            throw new ServiceException("组卷明细列表不能为空！");
        }
//        validEntityBeforeSave(juanGenerate);
        boolean flag = false;
        if (checkGenerateDetailIsLegal(juanGenerate, generateDetails)) {
            flag = tJuanGenerateMapper.insert(juanGenerate) > 0;
        }
        if (flag) {
            // 批量新增组卷明细列表
            insertGenerateDetailBatch(saveBean.getGenerateDetails(), juanGenerate.getGenerateId());
        }
        return flag;
    }

    /**
     * 检查组卷详情列表是否合法
     *
     * @param juanGenerate 组卷信息
     * @param list         组卷详情列表
     * @return 是否合法
     */
    private boolean checkGenerateDetailIsLegal(TJuanGenerate juanGenerate, List<TJuanGenerateDetail> list) {
        if (1 == juanGenerate.getGenerateNum()) {
            return true;
        }
        // 题目类型列表
        List<String> questionTypeList = list.stream().map(TJuanGenerateDetail::getQuestionType)
            .distinct().collect(Collectors.toList());
        // 题目范围列表（章节id列表/知识点id列表/试卷id列表）
        List<String> questionScopeList = Arrays.asList(juanGenerate.getGenerateScope().split(","));

        // 题目查询bean
        QuestionQueryBean questionQueryBean = new QuestionQueryBean();
        questionQueryBean.setCourseId(juanGenerate.getCourseId());
        questionQueryBean.setQuestionTypes(questionTypeList);
        // 所有题目列表，供随机选题
        List<PaperQuestionInfoBean> allQuestions = Lists.newArrayList();
        if (GenerateScopeType.KNOWLEDGE.getCode().equals(juanGenerate.getGenerateScopeType())) {
            questionQueryBean.setKnowledgeIds(questionScopeList);
            // 构建知识点的子节点id列表
            buildChapterKnowledgeChildIds(questionQueryBean);
            // 已选知识点和已选题型下的所有题目
            allQuestions = tJuanQuestionMapper.queryAutoGenerateQuestions(questionQueryBean);
        }
        // 试卷题目信息json列表
        List<String> paperQuestionInfoJsons = Lists.newArrayList();
        int totalPaperScore;
        // 生成多张试卷
        totalPaperScore = generateMultiPapersMethod(paperQuestionInfoJsons, juanGenerate, allQuestions, list);
        // 分数大于0则表示此方案能够生成试卷
        return totalPaperScore > 0;
    }

    /**
     * 修改组卷
     */
    @Override
    public Boolean updateByBo(GenerateSaveBean saveBean) {
        TJuanGenerate update = BeanUtil.toBean(saveBean, TJuanGenerate.class);
//        validEntityBeforeSave(update);
        List<TJuanGenerateDetail> generateDetails = saveBean.getGenerateDetails();
        int paperTotalScore = generateDetails.stream().mapToInt(o -> o.getQuestionNum() * o.getQuestionScore()).sum();
        if (paperTotalScore != saveBean.getPaperTotalScore()) {
            throw new ServiceException("题目总分与试卷总分不一致！");
        }
        generateDetails.forEach(item -> {
            item.setGenerateId(update.getGenerateId());
            item.setCreatedBy(String.valueOf(LoginHelper.getUserId()));
            item.setCreatedTime(DateUtils.getNowDate());
        });
        LambdaQueryWrapper<TJuanGenerateDetail> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(update.getGenerateId()), TJuanGenerateDetail::getGenerateId, update.getGenerateId());
        boolean flag = false;
        if (checkGenerateDetailIsLegal(update, generateDetails)) {
            flag = tJuanGenerateMapper.updateById(update) > 0;
        }
        if (flag) {
            tJuanGenerateDetailMapper.delete(lqw);
            tJuanGenerateDetailMapper.insertBatch(generateDetails);
        }
        return flag;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(TJuanGenerate entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除组卷
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        Boolean flag = tJuanGenerateMapper.deleteBatchIds(ids) > 0;
        if (flag) {
            LambdaQueryWrapper<TJuanGenerateDetail> lqw = Wrappers.lambdaQuery();
            lqw.in(TJuanGenerateDetail::getGenerateId, ids);
            tJuanGenerateDetailMapper.delete(lqw);
        }
        return flag;
    }

    /**
     * 生成单张试卷方法
     *
     * @param paperQuestionInfoJsons 试卷题目信息json列表
     * @param allQuestions           所有题目
     * @param generateDetails        筛选条件
     * @return 试卷总分
     */
    @Override
    public Integer generateSinglePaperMethod(List<String> paperQuestionInfoJsons,
                                             List<PaperQuestionInfoBean> allQuestions,
                                             List<TJuanGenerateDetail> generateDetails) {
        // 试卷总分
        int paperTotalScore = 0;
        // 试卷题目列表
        List<PaperQuestionInfoBean> paperQuestions = Lists.newArrayList();
        for (TJuanGenerateDetail generateDetail : generateDetails) {
            // 各类型各分数的题目列表
            List<PaperQuestionInfoBean> eachTypeQuestions = allQuestions.stream()
                .filter(item -> item.getQuestionType().equals(generateDetail.getQuestionType()))
                .filter(item -> item.getScore().equals(generateDetail.getQuestionScore()))
                .collect(Collectors.toList());
//            eachTypeQuestions.forEach(item -> item.setScore(generateDetail.getQuestionScore()));
            paperQuestions.addAll(difficultClassifyMethod(eachTypeQuestions, generateDetail));
            // 累加各个题型的所有分值
            paperTotalScore = paperTotalScore + (generateDetail.getQuestionNum() * generateDetail.getQuestionScore());
        }
        // 构建试卷题目信息json列表
        buildQuestionInfoJsons(paperQuestions, paperQuestionInfoJsons);
        return paperTotalScore;
    }

    /**
     * 生成多张试卷方法
     *
     * @param paperQuestionInfoJsons 试卷题目信息json列表
     * @param juanGenerate           组卷信息
     * @param allQuestions           所有题目
     * @param generateDetails        组卷明细列表
     * @return 试卷总分
     */
    private Integer generateMultiPapersMethod(List<String> paperQuestionInfoJsons, TJuanGenerate juanGenerate,
                                              List<PaperQuestionInfoBean> allQuestions,
                                              List<TJuanGenerateDetail> generateDetails) {
        // 每张试卷总题目数
        int totalQuestionNum = generateDetails.stream().mapToInt(TJuanGenerateDetail::getQuestionNum).sum();
        log.info("totalQuestionNum:{}", totalQuestionNum);
        // 试卷份数
        Integer generateNum = juanGenerate.getGenerateNum();
        // 重复率（试卷彼此之间的题目id重复率不能超过该数值）
        BigDecimal generateRepeat = juanGenerate.getGenerateRepeat();
        // 最大重复题目数
        int maxRepeatQuestionNum = generateRepeat.multiply(new BigDecimal(totalQuestionNum)).stripTrailingZeros().intValue();
        log.info("maxRepeatQuestionNum:{}", maxRepeatQuestionNum);
        // 最小不重复题目数
        int minQuestionNumOfUnRepeat = totalQuestionNum - maxRepeatQuestionNum;
        // 所有试卷总的最小不重复题目数
        int totalMinUnRepeatQuestionNum = generateNum * minQuestionNumOfUnRepeat;
        log.info("totalMinUnRepeatQuestionNum:{}", totalMinUnRepeatQuestionNum);
        if (0 == maxRepeatQuestionNum || 0 == totalMinUnRepeatQuestionNum) {
            throw new ServiceException("请重试或重新设置组卷参数！");
        }
        // 题目map（key：题目id, value：题目信息）
        HashMap<String, PaperQuestionInfoBean> questionMap = new HashMap<>();
        // 随机获取所有试卷总的最小不重复题目列表（用于随机等份分在每张试卷里面）
        List<PaperQuestionInfoBean> totalMinUnRepeatQuestions = randomTotalMinUnRepeatQuestions(questionMap, allQuestions,
            generateDetails, totalMinUnRepeatQuestionNum, generateNum);
        // 等份拆分总的最小不重复题目列表，然后填充每个类型下需要的题目
        int totalPaperScore = splitAndFill(paperQuestionInfoJsons, totalMinUnRepeatQuestions, allQuestions, generateDetails, generateNum,
            juanGenerate.getPaperTotalScore(), generateRepeat);
        int times = 1;
        while (0 == totalPaperScore) {
            totalPaperScore = splitAndFill(paperQuestionInfoJsons, totalMinUnRepeatQuestions, allQuestions, generateDetails, generateNum,
                juanGenerate.getPaperTotalScore(), generateRepeat);
            times++;
            if (MAX_RANDOM_TIMES == times) {
                throw new ServiceException("请重试或重新设置组卷参数！");
            }
        }
        return totalPaperScore;
    }

    /**
     * 筛选题目难易度并取出对应题目数的题目
     *
     * @param eachTypeQuestions 各类型的题目列表
     * @param generateDetail    题目难易度对应的题目数量信息
     * @return 经过难易度筛选并对应数量的题目
     */
    private List<PaperQuestionInfoBean> difficultClassifyMethod(List<PaperQuestionInfoBean> eachTypeQuestions,
                                                                TJuanGenerateDetail generateDetail) {
        // 各难易度的题目列表
        List<PaperQuestionInfoBean> eachEasyQuestions = eachTypeQuestions.stream().
            filter(item -> generateDetail.getQuestionEasy().equals(item.getQuestionEasy()))
            .collect(Collectors.toList());
        // 随机题目列表
        List<PaperQuestionInfoBean> randomQuestions = Lists.newArrayList();
        // 题目map（key：题目id, 题目信息）
        HashMap<String, PaperQuestionInfoBean> questionMap = new HashMap<>();
        // 题数
        Integer questionNum = generateDetail.getQuestionNum();
        // 随机选题
        randomQuestionsMethod(questionMap, eachEasyQuestions, questionNum);
        randomQuestions.addAll(questionMap.values());
        return randomQuestions;
    }

    /**
     * 随机选题
     *
     * @param difficultyClassifyMap       各种难易度题目map
     * @param difficultyClassifyQuestions 各种难易度对应的所有题目
     * @param questionNum                 各种难易度题目对应的数量
     */
    private void randomQuestionsMethod(Map<String, PaperQuestionInfoBean> difficultyClassifyMap,
                                       List<PaperQuestionInfoBean> difficultyClassifyQuestions,
                                       Integer questionNum) {
        if (0 == difficultyClassifyQuestions.size()) {
            throw new ServiceException("请重试或重新设置组卷参数！");
        }
        // 随机次数
        int times = 0;
        while (difficultyClassifyMap.size() < questionNum) {
            // 随机题目
            PaperQuestionInfoBean randomQuestion = difficultyClassifyQuestions.get((int) (Math.random() * difficultyClassifyQuestions.size()));
            difficultyClassifyMap.put(randomQuestion.getQuestionId(), randomQuestion);
            times++;
            if (MAX_RANDOM_TIMES == times) {
                throw new ServiceException("请重试或重新设置组卷参数！");
            }
        }
    }

    /**
     * 填充每个类型的题目列表需要的题目
     *
     * @param paperQuestionInfoJsons    试卷题目信息json列表
     * @param totalMinUnRepeatQuestions 所有试卷总的最小不重复题目列表
     * @param allQuestions              所有题目
     * @param generateDetails           组卷明细列表
     * @param generateNum               试卷份数
     * @param paperScore                试卷总分
     * @return 试卷总分
     */
    private Integer splitAndFill(List<String> paperQuestionInfoJsons, List<PaperQuestionInfoBean> totalMinUnRepeatQuestions,
                                 List<PaperQuestionInfoBean> allQuestions, List<TJuanGenerateDetail> generateDetails,
                                 Integer generateNum, Integer paperScore, BigDecimal generateRepeat) {
        // 试卷总分
        int totalPaperScore = 0;
        // 拆分不重复的题目列表
        List<List<PaperQuestionInfoBean>> distributionList = distributionList(totalMinUnRepeatQuestions,
            totalMinUnRepeatQuestions.size() / generateNum);
        // 移除已经拆分的题目列表
        allQuestions.removeAll(totalMinUnRepeatQuestions);
        // 用于保存随机拆分中生成的各类型题目数量超过当前类型需要生成的题目
        List<PaperQuestionInfoBean> removeQuestions = Lists.newArrayList();
        List<List<PaperQuestionInfoBean>> list = Lists.newArrayList();
        for (List<PaperQuestionInfoBean> unRepeatQuestions : distributionList) {
            // 完成筛选的题目列表
            List<PaperQuestionInfoBean> finishRandomQuestions = Lists.newArrayList();
            for (TJuanGenerateDetail generateDetail : generateDetails) {
                allQuestions.addAll(removeQuestions);
                // 当前题目类型、分数、难易度的题目列表
                List<PaperQuestionInfoBean> eachTypeQuestions = unRepeatQuestions.stream()
                    .filter(item -> item.getQuestionType().equals(generateDetail.getQuestionType())
                        && item.getQuestionEasy().equals(generateDetail.getQuestionEasy())
                        && item.getScore().equals(generateDetail.getQuestionScore())).collect(Collectors.toList());
                // 相关性列表
                List<String> relevanceList = eachTypeQuestions.stream().filter(item -> null != item.getRelevance())
                    .map(PaperQuestionInfoBean::getRelevance).collect(Collectors.toList());
                // 当前题目类型用于随机取题的题目列表
                List<PaperQuestionInfoBean> eachTypeQuestionsForRandom = allQuestions.stream()
                    .filter(item -> generateDetail.getQuestionType().equals(item.getQuestionType()))
                    .filter(item -> generateDetail.getQuestionScore().equals(item.getScore()))
                    // 过滤掉含相关性的题目
                    .filter(item -> !relevanceList.contains(item.getQuestionCode()))
                    .collect(Collectors.toList());
                // 当前题目类型、分数、难易度需要生成的题目数量
                int questionNum = generateDetail.getQuestionNum();
                if (ObjectUtil.isEmpty(eachTypeQuestions)) {
                    // 随机拆分的题目不包含当前题目类型、难易度
                    List<PaperQuestionInfoBean> fillQuestions = difficultClassifyMethod(eachTypeQuestionsForRandom, generateDetail);
                    eachTypeQuestions.addAll(fillQuestions);
                } else if (questionNum < eachTypeQuestions.size()) {
                    // 随机拆分的题目数量超过当前题目类型、分数、难易度需要生成的题目数量
                    for (int i = 0; i < eachTypeQuestions.size() - questionNum; i++) {
                        PaperQuestionInfoBean removeQuestion = eachTypeQuestions.remove(i);
                        removeQuestions.add(removeQuestion);
                    }
                } else if (questionNum > eachTypeQuestions.size()) {
                    // 随机拆分的题目数量不足当前题目类型、分数、难易度需要生成的题目数量
                    TJuanGenerateDetail bean = BeanCopyUtils.copy(generateDetail, new TJuanGenerateDetail());
                    bean.setQuestionNum(questionNum - eachTypeQuestions.size());
                    List<PaperQuestionInfoBean> fillQuestions = difficultClassifyMethod(eachTypeQuestionsForRandom, bean);
                    eachTypeQuestions.addAll(fillQuestions);
                }
                // 设置题目分值
//                eachTypeQuestions.forEach(o -> o.setScore(generateDetail.getQuestionScore()));

                totalPaperScore = totalPaperScore + (questionNum * generateDetail.getQuestionScore());
                // 当前题型、分数、难易度下需要的题目已经填充满
                if (questionNum == eachTypeQuestions.size()) {
                    finishRandomQuestions.addAll(eachTypeQuestions);
                }
            }
            if (list.size() > 0) {
                List<PaperQuestionInfoBean> paperQuestionInfos = BeanCopyUtils.copyList(finishRandomQuestions, PaperQuestionInfoBean.class);
                for (int i = 0; i < list.size(); i++) {
                    List<PaperQuestionInfoBean> paperQuestionInfoBeans = list.get(i);
                    paperQuestionInfos.retainAll(paperQuestionInfoBeans);
                    // 重复的题目总分
                    int sum = paperQuestionInfos.stream().mapToInt(PaperQuestionInfoBean::getScore).sum();
                    // 重复的题目总分与试卷总分占比
                    BigDecimal repeatQuestionsTotalScore = new BigDecimal(sum).divide(BigDecimal.valueOf(paperScore), 2, BigDecimal.ROUND_HALF_UP);
                    if (repeatQuestionsTotalScore.compareTo(generateRepeat) > 0) {
                        return 0;
                    }
                }
            }
            list.add(finishRandomQuestions);
            // 构建试卷题目信息json列表
            buildQuestionInfoJsons(finishRandomQuestions, paperQuestionInfoJsons);
        }
        return totalPaperScore / generateNum;
    }

    /**
     * 随机获取所有试卷最小不重复的题目列表（用于随机等份分在每张试卷里面）
     *
     * @param questionMap                 题目map
     * @param allQuestions                所有题目
     * @param generateDetails             组卷明细列表
     * @param totalMinUnRepeatQuestionNum 所有试卷最小不重复总题目数
     * @param generateNum                 试卷份数
     * @return 所有试卷总的最小不重复题目列表
     */
    private List<PaperQuestionInfoBean> randomTotalMinUnRepeatQuestions(Map<String, PaperQuestionInfoBean> questionMap,
                                                                        List<PaperQuestionInfoBean> allQuestions,
                                                                        List<TJuanGenerateDetail> generateDetails,
                                                                        Integer totalMinUnRepeatQuestionNum,
                                                                        Integer generateNum) {
        // 随机次数
        int times = 0;
        // 所有试卷不重复的总题目列表
        List<PaperQuestionInfoBean> totalMinUnRepeatQuestions = Lists.newArrayList();
        while (questionMap.size() < totalMinUnRepeatQuestionNum) {
            // 随机题目
            PaperQuestionInfoBean randomQuestion = allQuestions.get((int) (Math.random() * allQuestions.size()));
            for (TJuanGenerateDetail generateDetail : generateDetails) {
                if (generateDetail.getQuestionType().equals(randomQuestion.getQuestionType())
                    && generateDetail.getQuestionEasy().equals(randomQuestion.getQuestionEasy())) {
                    // 各类型下各分数各难度的题目数量
                    int eachTypeQuestionNum = (int) totalMinUnRepeatQuestions.stream()
                        .filter(paperQuestionInfoBean -> paperQuestionInfoBean.getQuestionType().equals(generateDetail.getQuestionType())
                            && paperQuestionInfoBean.getScore().equals(generateDetail.getQuestionScore())
                            && paperQuestionInfoBean.getQuestionEasy().equals(generateDetail.getQuestionEasy())).count();
                    if (eachTypeQuestionNum < (generateDetail.getQuestionNum() * generateNum)) {
                        totalMinUnRepeatQuestions.add(randomQuestion);
                        questionMap.put(randomQuestion.getQuestionId(), randomQuestion);
                    }
                }
            }
            times++;
            if (MAX_RANDOM_TIMES == times) {
                throw new ServiceException("请重试或重新设置组卷参数！");
            }
        }
        if (0 == totalMinUnRepeatQuestions.size()) {
            throw new ServiceException("请重试或重新设置组卷参数！");
        }
        return totalMinUnRepeatQuestions.stream().distinct().collect(Collectors.toList());
    }

    /**
     * 将一个list均分成n个list
     *
     * @param list 数据
     * @param size 批次大小
     * @return 分成n个list
     */
    public static <T> List<List<T>> distributionList(List<T> list, int size) {
        List<List<T>> result = Lists.newArrayList();
        //获取被拆分的数组个数
        int arrSize = list.size() % size == 0 ? list.size() / size : list.size() / size + 1;
        for (int i = 0; i < arrSize; i++) {
            List<T> value = Lists.newArrayList();
            //把指定索引数据放入到list中
            for (int j = i * size; j <= size * (i + 1) - 1; j++) {
                if (j <= list.size() - 1) {
                    //得到拆分后的集合
                    value.add(list.get(j));
                }
            }
            //将拆分后的集合综合为一个集合
            result.add(value);
        }
        return result;
    }

    /**
     * 批量新增试卷
     *
     * @param paperQuestionInfoJsons 试卷题目信息json列表
     * @param juanGenerate           组卷信息
     * @param totalPaperScore        组卷信息
     * @return 是否添加成功
     */
    private Boolean insertPaperBatch(List<String> paperQuestionInfoJsons, TJuanGenerate juanGenerate,
                                     Integer totalPaperScore) {
        // 课程id
        String courseId = juanGenerate.getCourseId();
        // 课程信息
        TJuanCourse juanCourse = tJuanCourseMapper.selectById(courseId);
        if (null == juanCourse) {
            throw new ServiceException("课程不存在！");
        }
        // 课程编码
        String courseCode = juanCourse.getCourseCode();
        LambdaQueryWrapper<TJuanPaper> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(courseId), TJuanPaper::getCourseId, courseId);
        lqw.orderByDesc(TJuanPaper::getPaperCode, TJuanPaper::getCreatedTime);
        List<TJuanPaper> juanPapersByCourseId = tJuanPaperMapper.selectList(lqw);
        int index;
        if (CollectionUtils.isEmpty(juanPapersByCourseId)) {
            index = 0;
        } else {
            // 最新的一份试卷
            TJuanPaper newestPaper = juanPapersByCourseId.get(0);
            // 最新试卷的试卷编码
            String newestPaperCode = newestPaper.getPaperCode();
            index = Integer.parseInt(newestPaperCode.substring(newestPaperCode.length() - 3));
        }
        // 试卷列表
        ArrayList<TJuanPaper> juanPapers = Lists.newArrayList();
        for (String paperQuestionInfoJson : paperQuestionInfoJsons) {
//            index++;
            TJuanPaper juanPaper = new TJuanPaper();
//            if (1 < paperQuestionInfoJsons.size()) {
//                juanPaper.setPaperName(juanGenerate.getPaperName() + getEightRandomCode());
//            } else {
            juanPaper.setPaperName(juanGenerate.getPaperName());
//                if (checkPaperNameIsExist(juanPaper.getPaperName())) {
//                    juanPaper.setPaperName(juanGenerate.getPaperName() + getEightRandomCode());
//                }
//            }
            juanPaper.setCourseId(courseId);
            juanPaper.setGenerateId(juanGenerate.getGenerateId());
            juanPaper.setPaperCode(courseCode + String.format("%03d", ++index));
            juanPaper.setPaperType(GeneratePaperType.AUTOMATIC.getKey());
            juanPaper.setPaperAttention(juanGenerate.getPaperAttention());
            juanPaper.setPaperSealLine(juanGenerate.getPaperSealLine());
            juanPaper.setPaperTime(juanGenerate.getPaperTime());
            juanPaper.setPaperTotalScore(totalPaperScore);
            juanPaper.setPaperEasy(juanGenerate.getGenerateEasy());
            juanPaper.setIsTakenOut(YesOrNo.NO.getKey());
            juanPaper.setPaperQuestionInfo(paperQuestionInfoJson);
            juanPaper.setCreatedBy(String.valueOf(LoginHelper.getUserId()));
            juanPaper.setCreatedTime(DateUtils.getNowDate());
            juanPapers.add(juanPaper);
            log.info("{}自动生成了试卷:{}", LoginHelper.getUsername(), juanPaper.getPaperName());
        }
        boolean flag = tJuanPaperMapper.insertBatch(juanPapers);
        if (flag) {
            // 批量新增试卷维护记录
//            insertPaperRecordBatch(juanPapers);
        }
        return flag;
    }

    /**
     * 获取试卷编码
     *
     * @param juanPaper  试卷信息
     * @param courseId   课程id
     * @param courseCode 课程编码
     * @return 试卷编码
     */
    private String getPaperCode(TJuanPaper juanPaper, String courseId, String courseCode) {
        LambdaQueryWrapper<TJuanPaper> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(courseId), TJuanPaper::getCourseId, courseId);
        lqw.orderByDesc(TJuanPaper::getCreatedTime);
        List<TJuanPaper> juanPapers = tJuanPaperMapper.selectList(lqw);
        if (CollectionUtils.isEmpty(juanPapers)) {
            return courseCode + "001";
        }
        // 最新的一份试卷
        TJuanPaper newestPaper = juanPapers.get(0);
        // 最新试卷的试卷编码
        String newestPaperCode = newestPaper.getPaperCode();
        int index = Integer.parseInt(newestPaperCode.substring(newestPaperCode.length() - 3));
        return courseCode + String.format("%03d", index + 1);
    }

    /**
     * 批量新增试卷维护记录
     *
     * @param juanPapers 试卷列表
     */
    private void insertPaperRecordBatch(List<TJuanPaper> juanPapers) {
        // 试卷维护记录列表
        ArrayList<TJuanPaperRecord> paperRecords = Lists.newArrayList();
        for (TJuanPaper juanPaper : juanPapers) {
            TJuanPaperRecord juanPaperRecord = new TJuanPaperRecord();
            juanPaperRecord.setPaperId(juanPaper.getPaperId());
            juanPaperRecord.setCourseId(juanPaper.getCourseId());
            juanPaperRecord.setPaperName(juanPaper.getPaperName());
            juanPaperRecord.setRecordType(PaperRecordType.AUTO_GENERATE.getKey());
            juanPaperRecord.setRecordContent(LoginHelper.getUsername() + PaperRecordType.AUTO_GENERATE.getValue() + "了试卷！");
            juanPaperRecord.setCreatedBy(String.valueOf(LoginHelper.getUserId()));
            juanPaperRecord.setCreatedTime(DateUtils.getNowDate());
            paperRecords.add(juanPaperRecord);
        }
        tJuanPaperRecordMapper.insertBatch(paperRecords);
    }

    /**
     * 批量新增组卷明细列表
     *
     * @param generateDetails 组卷明细列表
     * @param generateId      组卷id
     */
    private void insertGenerateDetailBatch(List<TJuanGenerateDetail> generateDetails, String generateId) {
        for (TJuanGenerateDetail generateDetail : generateDetails) {
            generateDetail.setGenerateId(generateId);
            generateDetail.setCreatedBy(String.valueOf(LoginHelper.getUserId()));
            generateDetail.setCreatedTime(DateUtils.getNowDate());
        }
        tJuanGenerateDetailMapper.insertBatch(generateDetails);
    }

    /**
     * 构建试卷题目信息json列表
     *
     * @param paperQuestions         试卷题目列表
     * @param paperQuestionInfoJsons 试卷题目信息json列表
     */
    private void buildQuestionInfoJsons(List<PaperQuestionInfoBean> paperQuestions, List<String> paperQuestionInfoJsons) {
        // 系统字典数据列表
        List<SysDictData> sysDictDataList = sysDictDataMapper.selectDictDataByType(DictTypeConstants.QUESTION_TYPE);
        // 字典数据map（key：字典键值，value：字典标签）
        Map<String, String> dictDataMap = sysDictDataList.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        // 题型详情列表（转成json，用于存入试卷表）
        List<QuestionTypeJsonBean> questionTypeDetails = Lists.newArrayList();
        Map<String, List<PaperQuestionInfoBean>> collect = paperQuestions.stream().collect(Collectors.groupingBy(PaperQuestionInfoBean::getQuestionType));
        for (Map.Entry<String, List<PaperQuestionInfoBean>> entry : collect.entrySet()) {
            // 题目类型
            String questionType = entry.getKey();
            // 题目列表
            List<PaperQuestionInfoBean> questionList = entry.getValue();
            QuestionTypeJsonBean questionTypeJsonBean = new QuestionTypeJsonBean();
            questionTypeJsonBean.setQuestionType(questionType);
            questionTypeJsonBean.setBigName(dictDataMap.get(questionType));
            questionTypeJsonBean.setBigDesc("（本大题共" + questionList.size() + "小题，" +
                "共" + questionList.size() * questionList.get(0).getScore() + "分）");
            questionTypeJsonBean.setQuestions(questionList);
            questionTypeDetails.add(questionTypeJsonBean);
        }
        paperQuestionInfoJsons.add(JsonUtils.toJsonString(questionTypeDetails));
    }

    /**
     * 构建章节知识点的子节点id列表
     *
     * @param questionQueryBean 题目查询bean
     */
    private void buildChapterKnowledgeChildIds(QuestionQueryBean questionQueryBean) {
        if (!ObjectUtil.isEmpty(questionQueryBean.getChapterIds())) {
            ArrayList<String> chapterIds = Lists.newArrayList();
            for (String chapterId : questionQueryBean.getChapterIds()) {
                chapterIds.addAll(tJuanChapterMapper.queryChildIdsById(chapterId));
            }
            questionQueryBean.setChapterIds(chapterIds);
        } else if (!ObjectUtil.isEmpty(questionQueryBean.getKnowledgeIds())) {
            ArrayList<String> knowledgeIds = Lists.newArrayList();
            for (String knowledgeId : questionQueryBean.getKnowledgeIds()) {
                knowledgeIds.addAll(tJuanKnowledgeMapper.queryChildIdsById(knowledgeId));
            }
            questionQueryBean.setKnowledgeIds(knowledgeIds);
        }
    }

    /**
     * 构建题量配比列表
     *
     * @param list 题量配比列表
     * @param map  key："题型_题目分数_难易程度", value: 总条数
     */
    private void buildQuestionCountProportions(List<QuestionTypePropertyBean> list, Map<String, Long> map) {
        for (String key : map.keySet()) {
            QuestionTypePropertyBean bean = new QuestionTypePropertyBean();
            String[] arr = key.split("_");
            String questionType = arr[0];
            Integer questionScore = Integer.valueOf(arr[1]);
            String questionEasy = arr[2];

            bean.setQuestionType(questionType);
            bean.setQuestionScore(questionScore);
            bean.setQuestionEasy(questionEasy);
            bean.setQuestionNum(map.get(key).intValue());
            list.add(bean);
        }
    }

    /**
     * 构建多试卷的题目信息列表
     *
     * @param paperIds          试卷id列表
     * @param questionInfoBeans 题目信息列表
     */
    private void buildPapersQuestionInfos(List<String> paperIds, List<PaperQuestionInfoBean> questionInfoBeans) {
        // 试卷列表
        List<TJuanPaper> juanPapers = tJuanPaperMapper.selectBatchIds(paperIds);
        if (CollectionUtils.isEmpty(juanPapers)) {
            throw new ServiceException("试卷不存在！");
        }
        // 课程id列表
        List<String> courseIds = juanPapers.stream().map(TJuanPaper::getCourseId).distinct().collect(Collectors.toList());
        if (1 < courseIds.size()) {
            throw new ServiceException("请选择同一个课程下的试卷！");
        }
        // 试卷题目信息json列表
        List<String> paperQuestionInfos = juanPapers.stream().map(TJuanPaper::getPaperQuestionInfo).collect(Collectors.toList());
        for (String paperQuestionInfo : paperQuestionInfos) {
            List<QuestionTypeJsonBean> questionTypeJsonBeans = JsonUtils.parseArray(paperQuestionInfo, QuestionTypeJsonBean.class);
            questionTypeJsonBeans.forEach(item -> questionInfoBeans.addAll(item.getQuestions()));
        }
    }

    /**
     * 检查试卷名称是否已存在
     *
     * @param paperName 试卷名称
     * @return 是否已存在
     */
    private Boolean checkPaperNameIsExist(String paperName) {
        LambdaQueryWrapper<TJuanPaper> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(paperName), TJuanPaper::getPaperName, paperName);
        List<TJuanPaper> juanPapers = tJuanPaperMapper.selectList(lqw);
        return juanPapers.size() > 0;
    }

    /**
     * 获取8位数不重复随机码（取当前时间戳转化为十六进制）
     *
     * @return 8位不重复随机码
     */
    public static String getEightRandomCode() {
        return Integer.toHexString((int) System.currentTimeMillis());
    }

    /**
     * 获取难度系数
     *
     * @param details 组卷明细列表
     * @return 难度系数
     */
    private BigDecimal getGenerateEasy(List<TJuanGenerateDetail> details) {
        // 题目难易度难度系数map，key：题目难度，value：难度系数
        Map<String, BigDecimal> easyMap = new HashMap<>();
        List<SysDictData> sysDictDataList = sysDictDataMapper.selectDictDataByType(DictTypeConstants.DIFFICULTY);
        // 默认难度系数，题目越难，难度系数越小
        BigDecimal generateEasy = new BigDecimal("0.75");
        for (int i = 0; i < sysDictDataList.size(); i++) {
            if (1 == sysDictDataList.size()) {
                easyMap.put(sysDictDataList.get(i).getDictValue(), generateEasy);
            } else {
                if (i == 0) {
                    DecimalFormat format = new DecimalFormat(".00");
                    generateEasy = new BigDecimal(format.format(1 - (1d / sysDictDataList.size())));
                }
                easyMap.put(sysDictDataList.get(i).getDictValue(), generateEasy);
                generateEasy = generateEasy.subtract(new BigDecimal("0.1"));
            }
        }
        // 题目难易度题目数量map，key：key：题目难度，value：题目数量
        Map<String, Integer> questionEasyMap = details.stream().collect(Collectors.groupingBy(TJuanGenerateDetail::getQuestionEasy,
            Collectors.summingInt(TJuanGenerateDetail::getQuestionNum)));
        // 题目总数
        int totalNum = details.stream().mapToInt(TJuanGenerateDetail::getQuestionNum).sum();
        BigDecimal totalEasy = new BigDecimal("0.00");
        for (Map.Entry<String, Integer> entry : questionEasyMap.entrySet()) {
            // 难度系数
            BigDecimal bigDecimal = easyMap.get(entry.getKey());
            if (ObjectUtil.isEmpty(bigDecimal)) {
                continue;
            }
            // 题目数量
            Integer value = entry.getValue();
            BigDecimal multiply = bigDecimal.multiply(BigDecimal.valueOf(value));
            totalEasy = totalEasy.add(multiply);
        }
        return totalEasy.divide(BigDecimal.valueOf(totalNum), 2, BigDecimal.ROUND_HALF_UP);
    }

}
